// Copyright 2013 Google Inc. All Rights Reserved.
//
// Defines the first element of ctors and dtors sections. All shared
// objects and executables should link this as the first object.
//
// Note: GCC 4.7 uses .init_array and .fini_array instead of .init,
// .fini, .ctors, and .dtors. Android is using GCC 4.7 and ARM NaCl uses
// GCC 4.8, so non-ARM part of this file does not correspond to other ports.
//

extern void *__dso_handle;
typedef void (*structor_fn)(void);

// The first entries of the global constructors/destructors. Note that
// we skip the first element, so we set invalid values for them. It
// seems the first elements of these lists are -1 and they are usually
// terminated by 0. Though we could find no standard which enforces
// this, we follow the custom.
__attribute__((section (".ctors")))
const structor_fn __CTOR_LIST__[1] = { (structor_fn)-1 };
__attribute__((section (".dtors")))
const structor_fn __DTOR_LIST__[1] = { (structor_fn)-1 };

// Unlike .ctors and .dtors, .eh_frame does not have a watchdog for
// the first element.
__attribute__((section (".eh_frame")))
static const int __EH_FRAME_BEGIN__[0] = {};

void __register_frame_info(const void* eh, void* obj);
void __deregister_frame_info(const void* eh);

__attribute__((unused, section(".init"), visibility("hidden")))
void _init(void) {
  // This is the max size of "struct object" in
  // http://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libgcc/unwind-dw2-fde.h;h=2bbc60a837c8e3a5d62cdd44f2ae747731f9c8f8;hb=HEAD
  // This buffer is used by libgcc. Unfortunately, it seems there are
  // no way to get the size of this struct.
  // Note that bionic/libc/arch-x86/bionic/crtbegin.S uses 24
  // (sizeof(void*) * 6) for this buffer, but we use 28 here because
  // it seems there can be one more element if
  // DWARF2_OBJECT_END_PTR_EXTENSION is enabled.
  static char buf[sizeof(void*) * 7];
  // Register the info in .eh_frame to libgcc. Though we are disabling
  // C++ exceptions, we want to do this for _Unwind_Backtrace.
  __register_frame_info(__EH_FRAME_BEGIN__, buf);
  const structor_fn *iter = __CTOR_LIST__;
  while (*++iter)
    (**iter)();
}

__attribute__((unused, section(".fini"), visibility("hidden")))
void _fini(void) {
  const structor_fn *iter = __DTOR_LIST__;
  while (*++iter)
    (**iter)();
  __deregister_frame_info(__EH_FRAME_BEGIN__);
}

#include <private/__dso_handle.h>
